#include <bits/stdc++.h>
using namespace std;
//************************************************
//左值引用与右值引用

void Test_Rvalue_Reference()
{
    //左值与右值的最主要区别在于该值能否被取地址，const修饰的变量，具备右值不被修改的属性，但其依然可以被取地址，依然是左值
    int leftVal = 100;
    int && a = 10;
    // int && c = leftVal;这里会报错，原因是不允许右值引用对左值进行引用
    int && c = move(leftVal);//move会返回该值的右值的引用
    c = 200;//打上断点调试发现，本应该是右值引用的c，居然可以修改值
    //事实就是如此，右值引用是可以修改值的,这个时候c，其实就是左值属性了。
    const int & b = 10;
}


//----------------------------------
void func(int &a){

}
void func(const int& a)
{

}
void func(int &&a)
{

}
void func(const int&&a)
{

}

//完美转发
template <typename T>
void PerfectRef(T&& x)
{
    int a = 0;
    func(a);
    func(10);
    func(x);//forward可以完美转发对象在传参过程种，对象本身的属性
    func(forward<T>(x));//forward可以完美转发对象在传参过程种，对象本身的属性
    //上面谈过，因为右值引用之后，实际编译器给这个引用的值，就搞成左值的属性了，为了维持这点，用forward就很好
}


//------------------------------------
class A{
    public:
    A(int && val = 10)
    :_a(val)
    {
        cout<<"A()"<<endl;
    }
    A(const A& t)
    {
        cout<<"Copy A&()\n";
    }
    A(A&& t)
    {
        cout<<"Copy A&&()\n";
    }
    ~A(){
        cout<<"~A()"<<endl;
    }
    int _a =10;
};

A GetA()
{
    A a;
    return a;
}

void Test_Perfect_Ref()
{
    A a = 1;//经过测试，在g++编译器会做优化，直接把这个局部变量改了作用域和生命周期，使得不需要再调用析构，拷贝构造等函数
    A b = GetA();
    //经过测试，再MSVC下（如VS2022，就不会做这个优化，这是G++编译在做的时候单独处理的
    //这样使得在这个环境下，没办法看见右值引用在构造函数里面，可以省去再开空间得优化，但是可以看见赋值
}
class I{
    public:
    I()
    {

    }
    I(I&& a)
    {
        //转移走a的资源就好
        cout<<"I &&\n";
    }
    I(const I& a)
    {
        //拷贝资源
        cout<<"const I& a\n";
    }
    I operator =(I&& a)
    {
        cout<<"I &&\n";
        return *this;
    }
    I operator =(const I& a)
    {
        cout<<"const I& a\n";
        return *this;
    }
    int a = 0;
    int*p = &a;
};

class V{
    public:
    int count = 0;
    I arr[10];
    void push(I && a)
    {
        arr[count++] = forward<I>(a);//用一个完美转发
    }
    void push(const I& a)
    {
        arr[count++] = a;
    }
};
